package com.hhxy.aspect;

import com.alibaba.fastjson.JSON;
import com.hhxy.annotation.ControllerLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author ghp
 * @date 2023/4/29
 * @title
 * @description
 */
@Component
@Aspect
@Slf4j
public class ControllerLogAspect {

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.hhxy.annotation.ControllerLog))")
    public void pt() {

    }


    /**
     * 环绕通知
     *
     * @param joinPoint 被增强的方法所封装的对象
     * @return
     */
    @Around("pt()")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        try {
            // 目标方法执行前打印日志
            handleBefore(joinPoint);
            // 注意：不要try catch，不然controller层的异常都被切面捕捉到了
            // 执行目标方法
            result = joinPoint.proceed();
            log.info("=======Start=======");
            handleAfter(result);
        } finally {
            // 结束后换行(System.lineSeparator()动态换行，linux和Windows的换行符不一样)
            log.info("=======End=======" + System.lineSeparator());
            System.out.println(System.lineSeparator());
            System.out.println(System.lineSeparator());
            System.out.println(System.lineSeparator());
        }
        return result;
    }

    /**
     * 后置通知
     */
    private void handleAfter(Object result) {
        // 打印出参
        log.info("Response       : {}", JSON.toJSONString(result));
    }

    /**
     * 前置通知
     */
    private void handleBefore(ProceedingJoinPoint joinPoint) {
        // SpringFrameWork提供的Context中得到 HttpServletRequest 对象（获取当前线程中的Request，从而动态获取URL）
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取增强方法上的注解对象
        ControllerLog controllerLog = this.getSystemLog(joinPoint);

        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}", request.getRequestURL());
        // 打印描述信息
        log.info("BusinessName   : {}", controllerLog.businessName());
        // 打印 Http method
        log.info("HTTP Method    : {}", request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}", request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", joinPoint.getArgs());
        // 打印出参
        log.info("Response       : {}", JSON.toJSONString(joinPoint.getArgs()));
        // 结束后换行
        log.info("=======End=======" + System.lineSeparator());
        System.out.println(System.lineSeparator());
        System.out.println(System.lineSeparator());
        System.out.println(System.lineSeparator());
    }

    /**
     * 获取增强方法上的注解对象
     *
     * @param joinPoint
     * @return
     */
    private ControllerLog getSystemLog(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        ControllerLog controllerLog = methodSignature.getMethod().getAnnotation(ControllerLog.class);
        return controllerLog;
    }
}

